home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / D-G / Driver 2.2 / driver.c next >
Encoding:
C/C++ Source or Header  |  1993-10-23  |  21.1 KB  |  697 lines  |  [TEXT/KAHL]

  1. /* driver.c  - version 2.2 - October 21, 1993 */
  2.  
  3. /*
  4.  *    The following code is to install and remove RAM drivers in the system
  5.  *    heap. Written by Pete Resnick with the help of J. Geagan, Joe Holt,
  6.  *    Tom Johnson, Michael A. Libes, Charles Martin, John Norstad, Phil
  7.  *    Shapiro, Eric Braun, David Brown and Matthias Urlichs. Feel free to
  8.  *    use this in your code, though I do ask that you give credit. Please
  9.  *    report any bugs to Pete Resnick - resnick@cogsci.uiuc.edu. Please read
  10.  *    the README file and check defines in drvrincludes.h before you use
  11.  *    this code!!
  12.  *
  13.  *    Change Log
  14.  *    ----------
  15.  *    Date:        Change:                                                Who:
  16.  *    -----        -------                                                ----
  17.  *    6/2/92        Changed ThinkCleanup so that it compiles and works    pr
  18.  *    6/22/92        Corrected declaration of DisableInterrupts            eb
  19.  *    7/1/92        Corrected declaration of DrvrInstall and DrvrRemove    eb/pr
  20.  *    10/15/92    Changed Get1SysRsrc to Get1SysXRsrc                    pr
  21.  *    10/18/92    Got rid of thinkReOpen; just return 1 from close    pr
  22.  *                Fixed up PtrInZone to make it a little quicker        pr
  23.  *    11/6/92        Got rid of auto initialize for newCode and oldCode    pr
  24.  *                Changed PBxxx calls to PBxxxSync                    pr
  25.  *    11/8/92        A little cleanup; moved a few things                pr
  26.  *    12/17/92    Added HNoPurge to Get1SysXRsrc                        db/pr
  27.  *    1/24/93        Fixed double deletion of DATA handle and dispose    db/pr
  28.  *                of code handle -- major changes to all ThinkXXX
  29.  *                routines and THINKProc.c
  30.  *    2/5/93        Made DriverAvail a little more efficent                pr
  31.  *    2/6/93        Re-wrote all of the Think routines and THINKProc.c    pr
  32.  *                so that the THINK proc is a pointer instead of a
  33.  *                handle (needed for locked drivers).
  34.  *    2/23/93        Passed drvrInstFlags to RemoveRAMDriver    from        pr
  35.  *                InstallRAMDriver error
  36.  *    10/21/93    Check for nil handles in RemoveRAMDriver            pr
  37.  *                Zero out close block in RemoveRAMDriver
  38.  *                Prettified GetDrvrRefNum
  39.  *                Moved DisableInterrupts, ResetInterrupts,
  40.  *                DrvrInstall, and DrvrRemove from driver.h to
  41.  *                drvrincludes.h
  42.  *                    
  43.  */
  44.  
  45. #include "drvrincludes.h"        /* Internal use and other include files    */
  46. #include "driver.h"                /* To be used in your application        */
  47.  
  48. /*
  49.  *    InstallRAMDriver will install the named driver into the system heap
  50.  *    return the driver reference number in refNum. The drvrInstFlags
  51.  *    parameter (defined in driver.h) specifies whether to call the
  52.  *    driver's open routine, whether the driver is written in THINK C
  53.  *    and therefore has a DATA resource, whether the driver has THINK C's
  54.  *    multiple segment option turned on, and finally whether the driver
  55.  *    is written in THINK C and can be closed and then opened again.
  56.  *    THINK C makes some assumptions about owned resources being available
  57.  *    which will have to be taken care of. See the ThinkInstall routine to
  58.  *    see how it is handled.
  59.  */
  60.  
  61. OSErr InstallRAMDriver(Str255 drvrName, short *refNum,
  62.                        drvrFlagBits drvrInstFlags)
  63. {
  64.     register DriverPtr drvrPtr;
  65.     register DCtlPtr ctlEntryPtr;
  66.     ResType rsrcType;
  67.     Handle drvrHandle;
  68.     OSErr errCode;
  69.     short rsrcID, unitNum;
  70.     IOParam openBlock;
  71.     Byte hndlState;
  72.     
  73.     /* Sanity check the flags */
  74.     if(!(drvrInstFlags & thinkDATA) && (drvrInstFlags & thinkMulSeg))
  75.         return(paramErr);
  76.  
  77.     /* Don't re-install a device driver */
  78.     if(GetDrvrRefNum(drvrName) != 0)
  79.         return(badUnitErr);
  80.  
  81.     /* Get the new unit number for the driver */
  82.     errCode = DriverAvail(&unitNum);
  83.     if(errCode != noErr)
  84.         return(errCode);
  85.  
  86.     /*    Get the driver resource in the system heap and non-purgeable */
  87.     errCode = Get1SysXRsrc(&drvrHandle, 'DRVR', 0, 0, drvrName);
  88.     if(errCode != noErr)
  89.         return(dInstErr);
  90.     
  91.     /* Save the resource ID for later use */
  92.     GetResInfo(drvrHandle, &rsrcID, &rsrcType, drvrName);
  93.     if((errCode = ResError()) == noErr) {
  94.         /* Now detach it */
  95.         DetachResource(drvrHandle);
  96.         errCode = ResError();
  97.     }
  98.     
  99.     /* Return on errors */
  100.     if(errCode != noErr) {
  101.         ReleaseResource(drvrHandle);
  102.         return(errCode);
  103.     }
  104.     
  105.     /* Patch the driver if we are using THINK C */
  106.     if(drvrInstFlags & thinkDATA) {
  107.         errCode = ThinkInit(drvrHandle, rsrcID, unitNum, drvrInstFlags);
  108.         /* Return on errors */
  109.         if(errCode != noErr) {
  110.             DisposHandle(drvrHandle);
  111.             return(errCode);
  112.         }
  113.     }
  114.     
  115.     /* Install DRVR with the refNum. The refNum is the -(unitNum + 1) */
  116.     hndlState = HGetState(drvrHandle);
  117.     HLock(drvrHandle);
  118.     errCode = DrvrInstall(drvrHandle, ~unitNum);
  119.     HSetState(drvrHandle, hndlState);
  120.  
  121.     /* Cleanup on errors */
  122.     if(errCode != noErr) {
  123.         if(drvrInstFlags & thinkDATA)
  124.             ThinkCleanup(drvrHandle, true);
  125.         DisposHandle(drvrHandle);
  126.         return(errCode);
  127.     }
  128.     
  129.     /* Move the important information to the driver entry */
  130.     ctlEntryPtr = *(GetDCtlEntry(~unitNum));
  131.     drvrPtr = *(DriverHandle)drvrHandle;
  132.     ctlEntryPtr->dCtlDriver = (Ptr)drvrHandle;
  133.     ctlEntryPtr->dCtlFlags = drvrPtr->drvrFlags | dRAMBased;
  134.     ctlEntryPtr->dCtlDelay = drvrPtr->drvrDelay;
  135.     ctlEntryPtr->dCtlEMask = drvrPtr->drvrEMask;
  136.     ctlEntryPtr->dCtlMenu = drvrPtr->drvrMenu;
  137.     
  138.     /* Open the driver */
  139.     if(drvrInstFlags & open) {
  140.         openBlock.ioCompletion = nil;
  141.         openBlock.ioNamePtr = drvrName;
  142.         openBlock.ioPermssn = fsCurPerm;
  143.         errCode = PBOpenSync((ParmBlkPtr)&openBlock);
  144.     }
  145.     
  146.     /* If an error occurred during the open, remove the DRVR */
  147.     if(errCode != noErr)
  148.         RemoveRAMDriver(~unitNum, drvrInstFlags);
  149.     else
  150.         *refNum = ~unitNum;
  151.     return(errCode);
  152. }
  153.  
  154. /*
  155.  *    RemoveRAMDriver removes the driver installed in the system heap by
  156.  *    InstallRAMDriver. Pass the same flags to RemoveRAMDriver that you
  157.  *    did to InstallRAMDriver. If THINK C resources were being used,
  158.  *    they will be removed. (See ThinkInit and ThinkCleanup)
  159.  */
  160.  
  161. OSErr RemoveRAMDriver(short refNum, drvrFlagBits drvrInstFlags)
  162. {
  163.     OSErr errCode = noErr;
  164.     Handle drvrHandle, drvrStorage;
  165.     DCtlHandle ctlEntryHndl;
  166.     IOParam closeBlock;
  167.     Byte hndlState;
  168.     
  169.     /* Get the driver control entry */
  170.     if((ctlEntryHndl = GetDCtlEntry(refNum)) == nil)
  171.         return(unitEmptyErr);
  172.         
  173.     /* Check for nil handle */
  174.     if(*ctlEntryHndl == nil)
  175.         return(nilHandleErr);
  176.     
  177.     /* Get the driver handle */
  178.     drvrHandle = (Handle)(**ctlEntryHndl).dCtlDriver;
  179.  
  180.     /* If the driver is open, close it */
  181.     if((**ctlEntryHndl).dCtlFlags & dOpened) {
  182.         closeBlock.ioCompletion = nil;
  183.         closeBlock.ioResult = 0;
  184.         closeBlock.ioNamePtr = nil;
  185.         closeBlock.ioVRefNum = 0;
  186.         closeBlock.ioRefNum = refNum;
  187.         closeBlock.ioPermssn = 0;
  188.         if((errCode = PBCloseSync((ParmBlkPtr)&closeBlock)) != noErr)
  189.             return(errCode);
  190.     }
  191.     
  192.     /* Hold onto the driver storage handle */
  193.     drvrStorage = (**ctlEntryHndl).dCtlStorage;
  194.     
  195.     /* Remove the driver */
  196.     hndlState = HGetState(drvrHandle);
  197.     HLock(drvrHandle);
  198.     errCode = DrvrRemove(refNum);
  199.     HSetState(drvrHandle, hndlState);
  200.     
  201.     /* Return on errors */
  202.     if(errCode != noErr)
  203.         return(errCode);
  204.     
  205.     /* Do THINK C stuff */
  206.     if(drvrInstFlags & thinkDATA)
  207.         ThinkCleanup(drvrHandle, drvrStorage != nil);
  208.  
  209.     /*
  210.      *    Since the driver has been detached, it will have to be disposed of
  211.      *    since DrvrRemove just does a ReleaseResource on the handle.
  212.      */
  213.     if(drvrHandle != nil)
  214.         DisposHandle(drvrHandle);
  215.  
  216.     return(noErr);
  217. }
  218.  
  219. /*
  220.  *    GetDrvrRefNum simply searches through each driver control entry
  221.  *    for a driver with the same name as that specified in drvrName.
  222.  *    If found, the reference number is returned. If no driver is found
  223.  *    by that name, 0 is returned. Reads the low-memory global UnitNtryCnt.
  224.  */
  225.  
  226. short GetDrvrRefNum(Str255 drvrName)
  227. {
  228.     short unitNum;
  229.     DCtlPtr curDCtlPtr, *curDCtlHndl, **UTableEntry;
  230.     DriverPtr curDrvrPtr;
  231.     
  232.     /* Start at UTableBase */
  233.     UTableEntry = UTABLEBASE;
  234.     
  235.     /* Walk through the Unit Table */
  236.     for(unitNum = 0; unitNum < UNITNTRYCNT; ++unitNum) {
  237.     
  238.         /* Get the entry at this point in the unit table and increment */
  239.         curDCtlHndl = *UTableEntry++;
  240.         
  241.         if(curDCtlHndl != nil) {
  242.  
  243.             /* Dereference the control entry */
  244.             curDCtlPtr = *curDCtlHndl;
  245.             
  246.             /* Get the pointer to the driver */
  247.             curDrvrPtr = (DriverPtr)curDCtlPtr->dCtlDriver;
  248.  
  249.             /* If this is a RAM driver, it's a handle. ROM is a pointer */
  250.             if((curDCtlPtr->dCtlFlags & dRAMBased) && (curDrvrPtr != nil))
  251.                 curDrvrPtr = *(DriverPtr *)curDrvrPtr;
  252.             
  253.             /* Does the driver name match? */
  254.             if(curDrvrPtr != nil)
  255.                 if(EqualString(drvrName, curDrvrPtr->drvrName,
  256.                                false, true))
  257.                     return(~unitNum);
  258.         }
  259.     }
  260.     return(0);
  261. }
  262.  
  263. /*
  264.  *    GrowUTable increases the size of the driver unit table by newEntries.
  265.  *    Interrupts must be disabled during this operation. Changes the
  266.  *    low-memory globals UTableBase and UnitNtryCnt.
  267.  */
  268.  
  269. OSErr GrowUTable(short newEntries)
  270. {
  271.     DCtlHandle *newUTableBase;
  272.     short oldSR;
  273.     
  274.     /* Make room for the new Unit Table */
  275.     newUTableBase =
  276.         (DCtlHandle *)NewPtrSysClear((long)((UNITNTRYCNT + newEntries) *
  277.                                             sizeof(DCtlHandle)));
  278.     if(MemError() != noErr)
  279.         return(MemError());
  280.  
  281.     /* Any Device Manager action now would be bad! */
  282.     oldSR = DisableInterrupts();
  283.     
  284.     /* Move the old Unit Table to the new Unit Table */
  285.     BlockMove(UTABLEBASE, newUTableBase,
  286.               (long)(UNITNTRYCNT * sizeof(DCtlHandle)));
  287.     DisposPtr((Ptr)UTABLEBASE);
  288.     UTABLEBASE = newUTableBase;
  289.     UNITNTRYCNT += newEntries;
  290.     
  291.     /* Renable interrupts */
  292.     ResetStatusRegister(oldSR);
  293.  
  294.     return(noErr);
  295. }
  296.  
  297. /*
  298.  *    DriverAvail finds the first available slot in the unit table to
  299.  *    install the new device driver. It will call GrowUTable if there is
  300.  *    not enough room in the current unit table. It will return the first
  301.  *    available slot between LOW_UNIT and UP_UNIT. Reads the low-memory
  302.  *    global UTableBase and may change as well as read the low-memory global
  303.  *    UnitNtryCnt.
  304.  */
  305.  
  306. OSErr DriverAvail(short *unitNum)
  307. {
  308.     short unitIndex;
  309.     Size UTableSize;
  310.     OSErr errCode = noErr;
  311.  
  312. #define LOW_UNIT        48        /* First Unit Table Entry to use        */
  313. #define NEW_UNIT        64        /* Size of a "normal" Unit Table        */
  314. #define MAX_UNIT        128        /* Maximum size of a Unit Table            */
  315. #define UP_UNIT            4        /* Size to bounce up Unit Table            */
  316.     
  317.     *unitNum = 0;
  318.     UTableSize = GetPtrSize((Ptr)UTABLEBASE) / sizeof(DCtlHandle);
  319.     
  320.     /* See if we have less than the minimum number of unit entries */
  321.     if(UNITNTRYCNT <= LOW_UNIT) {
  322.  
  323.         /* Try to make Unit Table the standard size */
  324.         if(UTableSize < NEW_UNIT)
  325.             errCode = GrowUTable(NEW_UNIT - UTableSize);
  326.  
  327.         /* If there is an error, see if there is enough room anyway */
  328.         if(errCode != noErr) {
  329.             if(UTableSize > LOW_UNIT) {
  330.                 UNITNTRYCNT = (UNITNTRYCNT + 4 < UTableSize ?
  331.                                UNITNTRYCNT + 4 :
  332.                                UTableSize);
  333.                 errCode = noErr;
  334.             }
  335.         }
  336.         if(errCode == noErr)
  337.             *unitNum = LOW_UNIT;
  338.         return(errCode);
  339.     }
  340.     
  341.     /* Look for an empty slot in what's already there */
  342.     for(unitIndex = LOW_UNIT;
  343.         (unitIndex < UNITNTRYCNT) && (*unitNum == 0);
  344.         ++unitIndex)
  345.         if(UTABLEBASE[unitIndex] == nil)
  346.             *unitNum = unitIndex;
  347.     
  348.     /* Unit Table full up to UnitNtryCnt, so increase it */
  349.     if(*unitNum == 0) {
  350.  
  351.         /* If there is space in the Unit Table, just up the count */
  352.         if(UTableSize > UNITNTRYCNT) {
  353.             *unitNum = UNITNTRYCNT;
  354.             UNITNTRYCNT += (UTableSize - UNITNTRYCNT < UP_UNIT ?
  355.                             UTableSize - UNITNTRYCNT :
  356.                             UP_UNIT);
  357.         
  358.         /* If there isn't enough space, try to make it bigger */
  359.         } else {
  360.             if(MAX_UNIT - UNITNTRYCNT != 0) {
  361.                 unitIndex = UNITNTRYCNT;
  362.                 errCode = GrowUTable(MAX_UNIT - UNITNTRYCNT < UP_UNIT ?
  363.                                      MAX_UNIT - UNITNTRYCNT :
  364.                                      UP_UNIT);
  365.                 if(errCode != noErr)
  366.                     return(errCode);
  367.                 *unitNum = unitIndex;
  368.             }
  369.         }
  370.     }
  371.     if(*unitNum == 0)
  372.         return(unitTblFullErr);
  373.     else
  374.         return(noErr);
  375. }
  376.  
  377.  
  378. /*
  379.  *    Get1SysXRsrc gets a handle to the requested resource making sure that
  380.  *    both the resource itself and the master pointer are in the system heap
  381.  *    and non-purgeable. The resource is returned in rsrcHndl. The resource
  382.  *    will be retrieved according to resource type and either resource name,
  383.  *    or resource index, or resource ID, in that order, whichever is
  384.  *    non-zero.
  385.  */
  386.  
  387. OSErr Get1SysXRsrc(Handle *rsrcHndl, ResType rsrcType, short rsrcID,
  388.                    short rsrcInd, StringPtr rsrcName)
  389. {
  390.     THz tempZone, tempSysZone;
  391.     OSErr errCode, ptrCode = noErr;
  392.     
  393.     /* Make sure everything loads in the system heap */
  394.     tempZone = GetZone();
  395.     tempSysZone = SystemZone();
  396.     SetZone(tempSysZone);
  397.     SetResLoad(true);
  398.     
  399.     /* Get the resource and make sure it is in the system heap */
  400.     do {
  401.         errCode = ptrCode;
  402.         if(rsrcName != nil)
  403.             *rsrcHndl = Get1NamedResource(rsrcType, rsrcName);
  404.         else if(rsrcInd != 0)
  405.             *rsrcHndl = Get1IndResource(rsrcType, rsrcInd);
  406.         else
  407.             *rsrcHndl = Get1Resource(rsrcType, rsrcID);
  408.         if(*rsrcHndl != nil) {
  409.             if(PtrInZone(tempSysZone, (Ptr)*rsrcHndl) &&
  410.                PtrInZone(tempSysZone, (Ptr)**rsrcHndl)) {
  411.                 HNoPurge(*rsrcHndl);
  412.                 errCode = noErr;
  413.             } else {
  414.                 ReleaseResource(*rsrcHndl);
  415.                 *rsrcHndl = nil;
  416.                 ptrCode = memAZErr;
  417.             }
  418.         } else {
  419.             if((errCode = ResError()) == noErr)
  420.                 errCode = resNotFound;
  421.         }
  422.     } while(errCode == noErr && *rsrcHndl == nil);
  423.     
  424.     /* Restore the zone to what it was */
  425.     SetZone(tempZone);
  426.     return(errCode);
  427. }
  428.  
  429. /*
  430.  *    PtrInZone just checks to see whether the specified pointer is within
  431.  *    the specified zone.
  432.  */
  433.  
  434. Boolean PtrInZone(THz theZone, Ptr thePtr)
  435. {
  436.     register unsigned long stripMask, testPtr, dataStart, dataLim;
  437.     
  438.     stripMask = (unsigned long)StripAddress((void *)0xFFFFFFFF);
  439.     dataStart = (unsigned long)&theZone->heapData & stripMask;
  440.     dataLim = (unsigned long)theZone->bkLim & stripMask;
  441.     testPtr = (unsigned long)thePtr & stripMask;
  442.     return((testPtr < dataLim) && (testPtr >= dataStart));
  443. }
  444.  
  445. /*
  446.  *    THINK C uses a DATA resource for storage and DCOD resources for
  447.  *    multiple segments in device drivers. THINK C makes two pretty bad
  448.  *    assumptions about these resources: (a) that the resource file will
  449.  *    be open when the resources are needed; and (b) that the resources
  450.  *    will be "owned" by the driver. Resource ownership is described in
  451.  *    Inside Macintosh I, but the important point is that the driver assumes
  452.  *    that its unit table number will correspond to its own resource ID and
  453.  *    to the resource ID's of resources it owns. Since the driver is going
  454.  *    to be installed in the first free unit table entry and will be detached
  455.  *    in the system heap, both of these assumptions are bad. To correct
  456.  *    these problems, the THINK C driver glue is patched. A pointer to a
  457.  *    small block of code is loaded into the system heap. Occurances of
  458.  *    GetResource calls in the THINK C driver glue are replaced by calls to
  459.  *    the new routine. The handles to the DATA (and DCOD) resource(s) are
  460.  *    stored along with the routine. So, when THINK C goes looking for its
  461.  *    owned resource(s), the appropriate handle(s) are returned instead.
  462.  *
  463.  *    ThinkInit gets all of the resources needed and installs the patch to
  464.  *    the THINK C glue. It takes as parameters the handle to the driver that
  465.  *    is to be patched, the original resource ID of the driver (to figure out
  466.  *    the resource ID's of the DATA and DCOD resources), the current unit
  467.  *    table number, and the drvrInstFlags.
  468.  */
  469.  
  470. OSErr ThinkInit(Handle drvrHandle, short rsrcID, short unitNum,
  471.                 drvrFlagBits drvrInstFlags)
  472. {
  473.     Handle codeHandle = nil;
  474.     Ptr codePtr;
  475.     Size codeSize;
  476.     OSErr errCode;
  477.     
  478.     /* Get the new procedure code */
  479.     codeHandle = Get1Resource('PROC', THINK_PROC);
  480.     if(codeHandle == nil) {
  481.         if((errCode = ResError()) == noErr)
  482.             errCode = resNotFound;
  483.         return(errCode);
  484.     }
  485.  
  486.     /* Add the DATA resource to the end of the code handle */
  487.     errCode = ThinkAddRsrcs(codeHandle, 'DATA', rsrcID, unitNum);
  488.  
  489.     if(errCode == noErr) {
  490.         /* Add the DCOD resources if this is a multi-segment driver */
  491.         if(drvrInstFlags & thinkMulSeg)
  492.             errCode = ThinkAddRsrcs(codeHandle, 'DCOD', rsrcID, unitNum);
  493.         
  494.         if(errCode == noErr) {
  495.         
  496.             /* Create a pointer in the system heap to hold the code */
  497.             codeSize = GetHandleSize(codeHandle);
  498.             codePtr = NewPtrSys(codeSize);
  499.             if(codePtr == nil)
  500.                 errCode = memFullErr;
  501.             else
  502.                 BlockMove(*codeHandle, codePtr, codeSize);
  503.         }
  504.  
  505.         /* Cleanup on errors */
  506.         if(errCode != noErr) {
  507.             HLock(codeHandle);
  508.             ThinkRmvRsrcs(*codeHandle, true, true);
  509.         }
  510.     }
  511.     
  512.     /* Get rid of the code resource */
  513.     ReleaseResource(codeHandle);
  514.  
  515.     if(errCode != noErr)
  516.         return(errCode);
  517.     
  518.     /* Patch the driver code for the DATA resource. */
  519.     errCode = ThinkChangeCode(drvrHandle, codePtr, 'DATA');
  520.     
  521.     /* If there are multiple segments, take care of them */
  522.     if((errCode == noErr) && (drvrInstFlags & thinkMulSeg))
  523.         errCode = ThinkChangeCode(drvrHandle, codePtr, 'DCOD');
  524.  
  525.     /* Cleanup on errors */
  526.     if(errCode != noErr)
  527.         ThinkRmvRsrcs(codePtr, false, true);
  528.     
  529.     return(errCode);
  530. }
  531.  
  532. /*
  533.  *    ThinkChangeCode changes the piece of the THINK C device driver glue
  534.  *    that has been compiled into the driver code. The call to _GetResource
  535.  *    that retrieves the driver's owned resources is replaced by a procedure
  536.  *    call (JSR) to some new code. The procedure that is to be called
  537.  *    instead, which is compiled separately and must be in this resource
  538.  *    file, is loaded into the system heap and its address is patched into
  539.  *    the driver code.
  540.  */
  541.  
  542. OSErr ThinkChangeCode(Handle drvrHandle, Ptr codePtr, ResType theType)
  543. {
  544.     OSErr errCode = noErr;
  545.     CodeChunk oldCode, newCode;
  546.     long *chunkPtr;
  547.  
  548.     /* Fill in oldCode with what the THINK C glue looks like now */
  549.     chunkPtr = (long *)&oldCode;
  550.     *chunkPtr++ = 0x50F80A5E;        /* ST ResLoad */
  551.     *chunkPtr++ = 0x598F2F3C;        /* SUBQ.L #4,A7 ; MOVE.L Imm.L,-(A7) */
  552.     *chunkPtr++ = theType;            /* ResType for _GetResource */
  553.     *chunkPtr++ = 0x3F00A9A0;        /* MOVE.W D0,-(A7) ; _GetResource */
  554.     *(short *)chunkPtr = 0x201F;    /* MOVE.L (A7)+,D0 */
  555.  
  556.     /* Fill in newCode with what we want the THINK C glue to look like */
  557.     chunkPtr = (long *)&newCode;
  558.     *chunkPtr++ = 0x598F2F3C;        /* SUBQ.L #4,A7 ; MOVE.L Imm.L,-(A7) */
  559.     *chunkPtr++ = theType;            /* ResType for the handle */
  560.     *chunkPtr++ = 0x3F004EB9;        /* MOVE.W D0,-(A7) ; JSR Imm.L */
  561.     *chunkPtr++ = (long)codePtr;    /* Code address for JSR */
  562.     *(short *)chunkPtr = 0x201F;    /* MOVE.L (A7)+,D0 */
  563.  
  564.     /* Search for the appropriate call to GetResource and fix it */
  565.     if(Munger(drvrHandle, 0L,
  566.               &oldCode, sizeof(CodeChunk),
  567.               &newCode, sizeof(CodeChunk)) < 0)
  568.         return(paramErr);
  569.     else
  570.         return(noErr);
  571. }
  572.  
  573. /*
  574.  *    ThinkAddRsrcs adds the appropriate resource handle(s), ID(s), and an
  575.  *    indicator for type (0 for DATA and 1 for DCOD) to the end of the code
  576.  *    that is passed in so that they can be found when the code is called.
  577.  */
  578.  
  579. OSErr ThinkAddRsrcs(Handle codeHandle, ResType theType, short rsrcID,
  580.                     short unitNum)
  581. {
  582.     OSErr errCode = noErr;
  583.     short index;
  584.     RsrcRec resRec;
  585.     Str255 rsrcName;
  586.     
  587.     /* Find out how many resources of the type there are */
  588.     index = Count1Resources(theType) - 1;
  589.     if(index < 0)
  590.         return(resNotFound);
  591.     
  592.     do {
  593.         /* Get the indexed resource */
  594.         errCode = Get1SysXRsrc(&resRec.rsrc, theType, 0, index + 1, nil);
  595.         if(errCode == noErr) {
  596.             GetResInfo(resRec.rsrc, &resRec.id, &theType, rsrcName);
  597.             
  598.             /*
  599.              *    If the GetResInfo failed or the ID says that this is not
  600.              *    owned by the driver, get rid of the resource. Otherwise
  601.              *    detach it.
  602.              */
  603.             if(((errCode = ResError()) != noErr) ||
  604.                (((resRec.id & 0x0FE0) >> 5) != rsrcID)) {
  605.                     ReleaseResource(resRec.rsrc);
  606.             } else {
  607.                 DetachResource(resRec.rsrc);
  608.                 if((errCode = ResError()) == noErr) {
  609.  
  610.                     /* Set the saved resource ID to what it "should" be */
  611.                     resRec.id &= ~0x0FE0;
  612.                     resRec.id |= (unitNum << 5);
  613.                     resRec.typ = theType;
  614.                     
  615.                     /* Add the handle to the end of the code */
  616.                     errCode = PtrAndHand(&resRec, codeHandle,
  617.                                          sizeof(resRec));
  618.                     if(errCode != noErr)
  619.                         DisposHandle(resRec.rsrc);
  620.                 } else {
  621.                     ReleaseResource(resRec.rsrc);
  622.                 }
  623.             }
  624.         }
  625.     } while((errCode == noErr) && (--index != -1));
  626.     
  627.     return(errCode);
  628. }
  629.  
  630. /*
  631.  *    ThinkCleanup gets rid of the THINK C detached resources.
  632.  */
  633.  
  634. void ThinkCleanup(Handle drvrHandle, Boolean rmvDATA)
  635. {
  636.     CodeChunk newCode, *drvrChunk;
  637.     long codeOffset = 0L, codeSize, *chunkPtr;
  638.     Ptr codePtr = nil;
  639.  
  640.     /* Fill in newCode with what the fixed THINK C glue looks like */
  641.     chunkPtr = (long *)&newCode;
  642.     *chunkPtr++ = 0x598F2F3C;        /* SUBQ.L #4,A7 ; MOVE.L Imm.L,-(A7) */
  643.     *chunkPtr++ = 'DATA';            /* ResType for the handle */
  644.     *chunkPtr++ = 0x3F004EB9;        /* MOVE.W D0,-(A7) ; JSR Imm.L */
  645.     *chunkPtr++ = 0L;                /* Code address for JSR */
  646.     *(short *)chunkPtr = 0x201F;    /* MOVE.L (A7)+,D0 */
  647.  
  648.     codeSize = sizeof(newCode) -
  649.                (sizeof(newCode.p3) + sizeof(newCode.inst7));
  650.  
  651.     /* Look for an occurance of "fixed" driver glue */
  652.     do {
  653.         codeOffset = Munger(drvrHandle, codeOffset, &newCode,
  654.                             codeSize, nil, 0);
  655.         
  656.         /* If we found something ... */
  657.         if(codeOffset >= 0) {
  658.  
  659.             drvrChunk = (CodeChunk *)*drvrHandle + codeOffset;
  660.             
  661.             /* Make sure the last instruction matches */
  662.             if(drvrChunk->inst7 == newCode.inst7)
  663.                 codePtr = drvrChunk->p3.codePtr;
  664.                 
  665.         }
  666.     } while((codePtr == nil) && (codeOffset >= 0));
  667.     
  668.     if(codePtr != nil) {        
  669.         ThinkRmvRsrcs(codePtr, false, rmvDATA);
  670.         DisposPtr(codePtr);
  671.     }
  672. }
  673.  
  674. /*
  675.  *    ThinkRmvRsrcs disposes of the handles attached to the end of the code
  676.  *    pointer (unless the handle is marked as the DATA resource has already
  677.  *    been disposed of by the driver glue) and sets them to nil.
  678.  */
  679.  
  680. void ThinkRmvRsrcs(Ptr codePtr, Boolean isHandle, Boolean rmvDATA)
  681. {
  682.     Size codeSize;
  683.     RsrcRec *resPtr;
  684.     
  685.     if(isHandle)
  686.         codeSize = GetHandleSize(RecoverHandle(codePtr));
  687.     else
  688.         codeSize = GetPtrSize(codePtr);
  689.  
  690.     /* Find the end of the code resource and work back until done */
  691.     resPtr = (RsrcRec *)(codePtr + codeSize);
  692.     while((--resPtr)->rsrc != nil) {
  693.         if(rmvDATA || resPtr->typ != 'DATA')
  694.             DisposHandle(resPtr->rsrc);
  695.         resPtr->rsrc = nil;
  696.     }
  697. }